﻿using CPPEI.Coolzon.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DT = CPPEI.Coolzon.Designtime.Metadata;

namespace CPPEI.Coolzon.Designer.Views
{
    /// <summary>
    /// 发布方案到服务的线程
    /// </summary>
    public static class PublishDataSourceToServerThread
    {
        private static bool s_isRunning;
        private static Thread s_thread;

        private static string s_solutionDir;
        private static string s_targetDir;
        private static List<ServiceProxy.DesignServiceRef.PublishedDataSource> DataSourceList;

        
        private static List<ServiceProxy.DesignServiceRef.PublishedDataSource> s_successList;

        private static List<ServiceProxy.DesignServiceRef.PublishedDataSource> s_failureList;

        private static string s_tempeSolutionId;

        private static Action<List<ServiceProxy.DesignServiceRef.PublishedDataSource>, List<ServiceProxy.DesignServiceRef.PublishedDataSource>> s_completed;
        private static ServiceProxy.PubServiceRef.PublishServiceClient s_pubSerClient;

        /// <summary>
        /// 开始发布
        /// </summary>
        /// <param name="solutionDir">方案所在的目录</param>
        /// <param name="solution">方案对象</param>
        /// <param name="completed">执行完成事件，（发布成功的数据源列表，发布失败的数据源列表）</param>
        public static void Start(List<ServiceProxy.DesignServiceRef.PublishedDataSource> dataSourceList, 
            Action<List<ServiceProxy.DesignServiceRef.PublishedDataSource>, List<ServiceProxy.DesignServiceRef.PublishedDataSource>> completed)
        {
            if(s_isRunning)
            {
                return;
            }

            s_successList = new List<ServiceProxy.DesignServiceRef.PublishedDataSource>();
            s_failureList = new List<ServiceProxy.DesignServiceRef.PublishedDataSource>();

            s_completed = completed;

            s_tempeSolutionId = Guid.NewGuid().ToString("N");

            DataSourceList = dataSourceList;

            s_pubSerClient = ServiceProxy.PubServiceProxyManager.Create();

            s_isRunning = true;
            s_thread = new Thread(Running);
            s_thread.Start();
        }

        public static void Stop()
        {
            if (s_isRunning && s_thread == null)
            {
                s_thread.Abort();
                s_isRunning = false;
                s_thread = null;
            }
        }

        private static void Running()
        {
            // 循环数据源进行发布
            foreach (var dataSource in DataSourceList)
            {
                // 发布到本地的一个临时目录
                string tempDataSourceFile = Designtime.Metadata.Storage.GetDataSourceFilePath(s_tempeSolutionId);

                Coolzon.Metadata.DataSource rtDataSource = Convert(dataSource);
               
                // 生成数据源文件
                if (Coolzon.Designtime.Metadata.Storage.SaveRTDataSourceFile(tempDataSourceFile, rtDataSource))
                {
                    string trancactionId = null;
                    if (Prepare(string.Empty, dataSource.Name, out trancactionId))
                    {
                        if (PublishFile(string.Empty, dataSource.Name, tempDataSourceFile, trancactionId))
                        {
                            if(Commit(string.Empty, dataSource.Name, trancactionId))
                            {
                                // 成功
                                s_successList.Add(dataSource);
                                continue;
                            }
                        }
                    }
                }

                // 删除临时数据源文件
                Designtime.Metadata.Storage.DeleteDataSourceFile(s_tempeSolutionId);

                // 添加到失败的列表中
                s_failureList.Add(dataSource);
            }

            if(s_completed!=null)
            {
                s_completed(s_successList, s_failureList);
            }
            s_isRunning = false;
            s_thread = null;
        }
        private static bool PublishFile(string solution, string dataSource, string filePath, string trancactionId)
        {
            Logger.DebugToTag(Library.LogTAG, string.Format("发布文件到服务器:{0}", filePath));
            try
            {
                using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    CPPEI.Coolzon.ServiceProxy.PubServiceRef.PublishDataSourceFileRequest request = new ServiceProxy.PubServiceRef.PublishDataSourceFileRequest(dataSource, solution, trancactionId, fileStream);
                    CPPEI.Coolzon.ServiceProxy.PubServiceRef.PublishDataSourceFileResponse response = s_pubSerClient.PublishDataSourceFile(request);
                    if (!response.IsSuccess)
                    {
                        Logger.ErrorToTag(Library.LogTAG, string.Format("发布方案:{0},数据源文件:{1}, Path:{2}失败", solution, dataSource, filePath));
                        return false;
                    }
                }
                Logger.DebugToTag(Library.LogTAG, string.Format("发布方案:{0},数据源文件:{1}, Path:{2}成功", solution, dataSource, filePath));
                return true;
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogTAG, string.Format("发布方案:{0},数据源文件:{1}, Path:{2}失败,ex:{3}", solution, dataSource, filePath, ex));
                return false;
            }
        }
        private static bool Prepare(string solution, string dataSource, out string trancactionId)
        {
            trancactionId = null;
            try
            {
                CPPEI.Coolzon.ServiceProxy.PubServiceRef.PreparePublishDataSourceRequest request = new ServiceProxy.PubServiceRef.PreparePublishDataSourceRequest(dataSource, string.Empty);
                CPPEI.Coolzon.ServiceProxy.PubServiceRef.PreparePublishDataSourceResponse response = s_pubSerClient.PreparePublishDataSource(request);
                if (response.IsSuccess)
                {
                    trancactionId = response.TrancactionId;
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogTAG, string.Format("准备发布方案:{0},数据源文件:{1}失败,ex:{2}", solution, dataSource, ex));
                return false;
            }
        }

        private static bool Commit(string solution, string dataSource, string trancactionId)
        {
            try
            {
                CPPEI.Coolzon.ServiceProxy.PubServiceRef.CommitPublishDataSourceRequest request = new ServiceProxy.PubServiceRef.CommitPublishDataSourceRequest(dataSource, solution, trancactionId);
                CPPEI.Coolzon.ServiceProxy.PubServiceRef.CommitPublishDataSourceResponse response = s_pubSerClient.CommitPublishDataSource(request);
                if (response.IsSuccess)
                {
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogTAG, string.Format("提交发布完成方案:{0},数据源文件:{1}失败,ex:{1}", solution, dataSource, ex));
                return false;
            }
        }

        private static bool Cancel(string solution, string dataSource, string trancactionId)
        {
            try
            {
                CPPEI.Coolzon.ServiceProxy.PubServiceRef.CancelPublishDataSourceRequest request = new ServiceProxy.PubServiceRef.CancelPublishDataSourceRequest(dataSource, solution, trancactionId);
                CPPEI.Coolzon.ServiceProxy.PubServiceRef.CancelPublishDataSourceResponse response = s_pubSerClient.CancelPublishDataSource(request);
                if (response.IsSuccess)
                {
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag(Library.LogTAG, string.Format("撤销发布方案{0},数据源:{0}失败,ex:{1}", solution, dataSource, ex));
                return false;
            }
        }

        /// <summary>
        /// 将WCF dataSource转化为RuntimeMetadata.DataSource
        /// </summary>
        /// <param name="mDataSource"></param>
        /// <returns></returns>
        public static Coolzon.Metadata.DataSource Convert(ServiceProxy.DesignServiceRef.PublishedDataSource mDataSource)
        {
            Coolzon.Metadata.DataSource dataSource = new Metadata.DataSource();
            dataSource.Name = mDataSource.Name;
            dataSource.Caption = mDataSource.Caption;
            dataSource.Type = mDataSource.Type;
            dataSource.Version = mDataSource.PublishedVersion;
            dataSource.RuntimeVersion = mDataSource.RTVersion;
            dataSource.CacheMode = Coolzon.Metadata.DataSource.TryParseCacheMode("Share");
            dataSource.Address = mDataSource.Address;

            dataSource.Authentication = new Metadata.Authentication();
            dataSource.Authentication.User = mDataSource.AuthenticationUser;
            dataSource.Authentication.Mode = mDataSource.AuthenticationMode;
            dataSource.Authentication.Password = mDataSource.AuthenticationPassword;

            dataSource.DataSets = new List<Metadata.DataSet>();
            //data set
            foreach (var mDataSet in mDataSource.DataSet)
            {
                Coolzon.Metadata.DataSet dataSet = new Metadata.DataSet();
                dataSet.CacheMode = Coolzon.Metadata.DataSource.TryParseCacheMode("Share");
                dataSet.Caption = mDataSet.Caption;
                dataSet.Name = mDataSet.Name;
                dataSet.Type = mDataSet.Type;
                dataSet.ValueString = mDataSet.ValueString;
                dataSet.Parameters = new List<Metadata.Parameter>();

                // parameters
                foreach (var mParameter in mDataSet.Parameters)
                {
                    Coolzon.Metadata.Parameter parameter = new Metadata.Parameter();

                    parameter.Caption = mParameter.Caption;
                    parameter.Name = mParameter.Name;
                    parameter.ValueType = mParameter.ValueType;

                    dataSet.Parameters.Add(parameter);
                }

                dataSource.DataSets.Add(dataSet);
            }

            return dataSource;
        }
    }
}
